/***********************************************************************
 * Fulguro Example 2
 * Example for testing two implementation of geodesic reconstruction
 *  - A fast way using fifo
 *  - A naive way using basic mathematical definition
 ***********************************************************************/
/*! 
 * \example example2.c <B>Geodesic reconstruction</B>
 */

#include <flgrCoreTypes.h>
#include <flgrCoreErrors.h>
#include <flgrCoreData.h>
#include <flgrCoreCompare.h>
#include <flgrCoreVector.h>
#include <flgrArith.h>
#include <flgrImageIO.h>
#include <flgrMorphoBase.h>

#include <time.h>

#define BENCH_FUNCTION(nbtime,textinfo,function,...)			\
  {									\
    time_t before_t, after_t;						\
    clock_t before_c, after_c;						\
    int i;								\
									\
    before_t = time(NULL);						\
    before_c = clock();							\
									\
    for(i=0;i<nbtime;i++) {						\
      function(__VA_ARGS__);						\
    }									\
    									\
    after_t = time(NULL);						\
    after_c = clock();							\
									\
    printf(textinfo " System time : %d us, CPU time : %d us \n",	\
	   (int) (((after_t-before_t)*1000000)/nbtime),			\
	   (int) ((after_c-before_c)/(CLOCKS_PER_SEC/1000000)/nbtime)); \
  }




/*******************************************************************************
 * Naive Geodesic Reconstruction by dilation
 *******************************************************************************/
FLGR_Ret geodesic_rec_dilate(FLGR_Data2D *immarker, FLGR_Data2D *immask, FLGR_Data2D *nhbc) {
  FLGR_Data2D *nhb,*imtmp1,*imtmp2;
  FLGR_Ret ret;

  nhb = flgr2d_create_neighborhood_from_connexity(immarker->spp,immarker->type, nhbc->connexity);

  imtmp1 = flgr2d_create_pixmap(immarker->size_y,immarker->size_x,immarker->spp,immarker->type);
  imtmp2 = flgr2d_create_pixmap(immarker->size_y,immarker->size_x,immarker->spp,immarker->type);
    
  if((ret=flgr2d_copy(imtmp2,immarker))!=FLGR_RET_OK) goto fail;  
  if((ret=flgr2d_dilate(imtmp1,imtmp2,nhb))!=FLGR_RET_OK) goto fail;
  if((ret=flgr2d_arith_inf(imtmp2,immask,imtmp1))!=FLGR_RET_OK) goto fail;

  while(flgr2d_compare(immarker,"==",imtmp2)==0) {
    if((ret=flgr2d_copy(immarker,imtmp2))!=FLGR_RET_OK) goto fail;
    if((ret=flgr2d_dilate(imtmp1,imtmp2,nhb))!=FLGR_RET_OK) goto fail;
    if((ret=flgr2d_arith_inf(imtmp2,immask,imtmp1))!=FLGR_RET_OK) goto fail;
  }
  
 fail:
  flgr2d_destroy(nhb);
  flgr2d_destroy(imtmp1);
  flgr2d_destroy(imtmp2);
  
  return ret;

}

/*******************************************************************************
 * Naive Geodesic Reconstruction by erosion
 *******************************************************************************/
FLGR_Ret geodesic_rec_erode(FLGR_Data2D *immarker, FLGR_Data2D *immask, FLGR_Data2D *nhbc) {
  FLGR_Data2D *nhb,*imtmp1,*imtmp2;
  FLGR_Ret ret;

  nhb = flgr2d_create_neighborhood_from_connexity(immarker->spp,immarker->type, nhbc->connexity);

  imtmp1 = flgr2d_create_pixmap(immarker->size_y,immarker->size_x,immarker->spp,immarker->type);
  imtmp2 = flgr2d_create_pixmap(immarker->size_y,immarker->size_x,immarker->spp,immarker->type);
    
  if((ret=flgr2d_copy(imtmp2,immarker))!=FLGR_RET_OK) goto fail;  
  if((ret=flgr2d_erode(imtmp1,imtmp2,nhb))!=FLGR_RET_OK) goto fail;
  if((ret=flgr2d_arith_sup(imtmp2,immask,imtmp1))!=FLGR_RET_OK) goto fail;

  while(flgr2d_compare(immarker,"==",imtmp2)==0) {
    if((ret=flgr2d_copy(immarker,imtmp2))!=FLGR_RET_OK) goto fail;
    if((ret=flgr2d_erode(imtmp1,imtmp2,nhb))!=FLGR_RET_OK) goto fail;
    if((ret=flgr2d_arith_sup(imtmp2,immask,imtmp1))!=FLGR_RET_OK) goto fail;
  }
  
 fail:
  flgr2d_destroy(nhb);
  flgr2d_destroy(imtmp1);
  flgr2d_destroy(imtmp2);
  
  return ret;

}

/*******************************************************************************
 * Naive Geodesic Reconstruction by openning
 *******************************************************************************/
FLGR_Ret geodesic_rec_open(FLGR_Data2D *imdest,FLGR_Data2D *imin,FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  if((ret=flgr2d_erode(imdest,imin,nhb))!=FLGR_RET_OK) return ret;  
  ret=geodesic_rec_dilate(imdest,imin,nhb);

  return ret;
}

/*******************************************************************************
 * Naive Geodesic Reconstruction by closing
 *******************************************************************************/
FLGR_Ret geodesic_rec_close(FLGR_Data2D *imdest,FLGR_Data2D *imin,FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  if((ret=flgr2d_dilate(imdest,imin,nhb))!=FLGR_RET_OK) return ret;  
  ret=geodesic_rec_erode(imdest,imin,nhb);

  return ret;
}
  

/*******************************************************************************
 * Naive Geodesic open tophat
 *******************************************************************************/
FLGR_Ret geodesic_rec_open_tophat(FLGR_Data2D *imdest,FLGR_Data2D *imin,FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  if((ret=geodesic_rec_open(imdest,imin,nhb))!=FLGR_RET_OK) return ret;  
  ret=flgr2d_arith_sub(imdest,imin,imdest);

  return ret;
}

/*******************************************************************************
 * Naive Geodesic close tophat
 *******************************************************************************/
FLGR_Ret geodesic_rec_close_tophat(FLGR_Data2D *imdest,FLGR_Data2D *imin,FLGR_Data2D *nhb) {
  FLGR_Ret ret;

  if((ret=geodesic_rec_close(imdest,imin,nhb))!=FLGR_RET_OK) return ret;  
  ret=flgr2d_arith_sub(imdest,imdest,imin);

  return ret;
}




int main(void) {
  FLGR_Data2D *imin;
  FLGR_Data2D *imDest1;
  FLGR_Data2D *imDest2;
  FLGR_Data2D *imDest3;
  FLGR_Data2D *imDest4;
  FLGR_Data2D *nhb;
  FLGR_Data2D *nhb2;

  imin    = flgr2d_load_pgm("../../images/gray/lena.pgm");
  //imin    = flgr2d_create_pixmap(256,1024,1,FLGR_UINT8);
  imDest1 = flgr2d_create_pixmap_from(imin);
  imDest2 = flgr2d_create_pixmap_from(imin);
  imDest3 = flgr2d_create_pixmap_from(imin);
  imDest4 = flgr2d_create_pixmap_from(imin);
  nhb     = flgr2d_create_neighborhood(9,9,1,FLGR_UINT8,FLGR_HEX,FLGR_6_CONNEX);
  nhb2    = flgr2d_create_neighborhood_from_connexity(1,FLGR_UINT8,FLGR_8_CONNEX);
  

  flgr2d_dilate(imDest1, imin, nhb);
  flgr2d_copy(imDest2,imDest1);
  flgr2d_copy(imDest3,imDest1);

  BENCH_FUNCTION(100000,"Erode 3x3 benchmark", flgr2d_erode,imDest4,imin,nhb2);

  BENCH_FUNCTION(100,"Fast Dual Geodesic reconstruction",
		flgr2d_geodesic_reconstruct_dual,imDest1,imin,nhb->connexity);

  BENCH_FUNCTION(100,"Fast Geodesic reconstruction by closing",
		flgr2d_geodesic_reconstruct_erode,imDest2,imin,nhb->connexity);

  BENCH_FUNCTION(100,"Naive Geodesic reconstruction by closing",
		geodesic_rec_erode,imDest3,imin,nhb);

  flgr2d_save_pgm(imDest1,"fast_dual.pgm",5);
  flgr2d_save_pgm(imDest2,"fast.pgm",5);
  flgr2d_save_pgm(imDest3,"dual.pgm",5);

  flgr2d_destroy(imin);
  flgr2d_destroy(imDest1);
  flgr2d_destroy(imDest2);
  flgr2d_destroy(imDest3);
  flgr2d_destroy(imDest4);
  flgr2d_destroy(nhb);
  flgr2d_destroy(nhb2);
}


